package com.citep.web.gwt.widgets;

import java.util.ArrayList;
import java.util.HashMap;

import com.citep.web.gwt.cache.AccountTreeCache;
import com.citep.web.gwt.cache.AccountTreeListener;
import com.citep.web.gwt.dto.AccountDTO;
import com.citep.web.gwt.dto.AccountTreeNode;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FocusListener;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

public class AccountTextField  extends TextBox implements AccountTreeListener, KeyboardListener, SuggestionListener,EditableWidget {

	private AccountTreeCache cache;
	private String previousText = "";
	private EditableWidgetListener listener;
	private String tableStyle;
	private String highLightStyle;
	private AccountDTO selectedAccount;
	
	private HashMap suggestionsToAccount = new HashMap();
	
	private static AccountAutoSuggest suggester;
	
	public void initializeSuggestions() {
		getSuggester().clearSuggestions();
		suggestionsToAccount.clear();
		cache.getAccountTree(this);
	}
	
	private static AccountAutoSuggest getSuggester() {
		if(suggester == null) {
			suggester = new AccountAutoSuggest(10);
			suggester.setVisible(false);
		}
		return suggester;
	}

	public void initialize(String value) {
		previousText = value;
		setText(value);
		if(getText().length() > 0)
			selectAll();

		initializeSuggestions();
		getSuggester().setTableStyle(tableStyle);
		getSuggester().setHighlightStyle(highLightStyle);
		setFocus(true);
		selectedAccount = null;
	}
	
	public void setEditableWidgetListener(EditableWidgetListener l) {
		listener = l;
	}

	
	public AccountTextField(String text, String editBoxStyle, String tableStyle, String highLightStyle) {
		cache = AccountTreeCache.getCache();
		
		setStyleName(editBoxStyle);
		this.tableStyle = tableStyle;
		this.highLightStyle = highLightStyle;

		addFocusListener(new FocusListener() {
			public void onFocus(Widget sender) {
				
			}

			public void onLostFocus(Widget sender) {
				commitEdit();
			}
		});
		
		addKeyboardListener(this);
	}
	
	
	private boolean validateBox() {
		return getText().length() > 0 && suggestionsToAccount.containsKey(getText());
	}

	private void commitEdit() {
		if(validateBox()) {
			String newText = getText();
			
			if(suggestionsToAccount.containsKey(newText))
				selectedAccount = (AccountDTO)suggestionsToAccount.get(newText);
			
			if(listener != null)
				listener.onEditComplete(newText);
			getSuggester().hide();
		} else {			
			Window.alert("Invalid account name.");
			setFocus(true);
		}
	}
	
	private void rollBackEdit() {
		if(listener != null)
			listener.onEditCancelled(previousText);
		setText(previousText);
	}
	
	
	public AccountDTO getSelectedAccount() {
		return selectedAccount;
	}

	public void onAccountTreeCurrent() { }

	public void onAccountTreeLoadFailure(Throwable t) { }

	public void addAccountToSuggestions(AccountTreeNode node, String parentName) {

		//"fully qualified account name, so that there are no collitions between
		//accounts who have the same name in different parent nodes
		String fqan = "";
		
		if(parentName != null && parentName.length() > 0) {
			fqan = parentName + " : " + node.getAccount().getName();
		} else {
			fqan = node.getAccount().getName();
		}
		
		getSuggester().addSuggestion(fqan);
		suggestionsToAccount.put(fqan, node.getAccount());
		
		ArrayList children = node.getChildren();
		if(children != null) {
			for(int i = 0; i < children.size(); i++) {
				addAccountToSuggestions((AccountTreeNode)children.get(i), fqan);
			}
		}		
	}
	
	public void onAccountTreeReady(AccountTreeNode root) {
		ArrayList children = root.getChildren();
		if(children != null) {
			for(int i = 0; i < children.size(); i++) {
				addAccountToSuggestions((AccountTreeNode)children.get(i),"");
			}
		}
	}

	public void onKeyDown(Widget sender, char keyCode, int modifiers) {
		// TODO Auto-generated method stub
		
	}

	public void processInput() {
		if(!getSuggester().isVisible()) {
			
			int suggestOffsetWidth = 250; //idaelly use getSuggester().getOffsetWidth(), but since it's not on screen it returns 0
			
			int yCoord = getAbsoluteTop() + getOffsetHeight();
			int right = getAbsoluteLeft() + suggestOffsetWidth;
			
			int xCoord;
			if(Window.getClientWidth() < right)
				xCoord = getAbsoluteLeft() + getOffsetWidth() - suggestOffsetWidth;
			else
				xCoord = getAbsoluteLeft();
			
			getSuggester().setPopupPosition(xCoord, yCoord);
			
			getSuggester().setSuggestionListener(this);
			getSuggester().setVisible(true);
			getSuggester().show();
			System.out.println("init suggester");
			
		}
		
		System.out.println("sending: " + getText());
		getSuggester().textChanged(getText());
	}
	
	public void onKeyPress(Widget sender, char keyCode, int modifiers) {
	}

	public void onKeyUp(Widget sender, char keyCode, int modifiers) {
		// TODO Auto-generated method stub
		switch(keyCode) {
			case KEY_ENTER:
				String suggestion = getSuggester().getCurrentSuggestion();
				onSuggestionClicked(suggestion);
			case KEY_DOWN:
				getSuggester().scrollDown();
				break;
			case KEY_UP:
				getSuggester().scrollUp();
				break;
			case KEY_ESCAPE:
				getSuggester().hide();
				rollBackEdit();
				break;
			default:
				processInput();
				break;
		}	
	}

	public void onSuggestionChanged(String suggestion) {
		// TODO Auto-generated method stub
		
	}
	
	public void onSuggestionClicked(String suggestion) {
		//the user has clicked on one of the suggestions
		setText(suggestion);
		commitEdit();
		getSuggester().setVisible(false);
		getSuggester().hide();
	}
}
